package br.hm.operandroid.manager;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.content.Context;
import android.database.Cursor;
import android.provider.CallLog;
import android.provider.Contacts;
import br.hm.operandroid.CallPhone;
import br.hm.operandroid.CallPhoneComparator;
import br.hm.operandroid.ContactPhone;
import br.hm.operandroid.ContactPhoneComparator;
import br.hm.operandroid.GenericGroup;
import br.hm.operandroid.SearchCallPhone;
import br.hm.telephoneoperator.CallOperatorException;
import br.hm.telephoneoperator.CallOperatorService;
import br.hm.telephoneoperator.Phone;
import br.hm.telephoneoperator.PhoneOperator;
import br.hm.telephoneoperator.PhonePortabilityDetail;
import br.hm.util.PhoneUtils;

@SuppressWarnings("deprecation")
public abstract class ContactTelephoneOperatorManager {

	protected CallOperatorService callOperatorService;
	protected Context context;

	public String getDDDDefault() {
		String ddd = Configurator.getDDDDefault(context);
		ddd = ddd == null ? "11" : ddd;
		return ddd;
	}

	public ContactTelephoneOperatorManager(
			CallOperatorService callOperatorService, Context context) {
		this.callOperatorService = callOperatorService;
		this.context = context;
	}

	public abstract void updateLabelContactTelephoneOperator(
			List<ContactPhone> contactPhones) throws CallOperatorException;

	public List<GenericGroup> countContactOperator()
			throws CallOperatorException {
		List<ContactPhone> contactPhones = listAllContactPhone();
		if (contactPhones.size() == 0) {
			return Collections.emptyList();
		}

		Set<Phone> phones = new HashSet<Phone>(contactPhones.size());
		for (ContactPhone contactPhone : contactPhones) {
			phones.add(contactPhone.phone);
		}

		List<PhonePortabilityDetail> phonePortabilityDetails = callOperatorService
				.getLastPhonePortabilityDetail(phones);

		Map<String, GenericGroup> map = new HashMap<String, GenericGroup>();

		for (PhonePortabilityDetail phonePortabilityDetail : phonePortabilityDetails) {
			PhoneOperator phoneOperator = phonePortabilityDetail
					.getPhoneOperator();
			String name = phoneOperator.getName().trim().toUpperCase();
			GenericGroup genericGroup = map.get(name);
			if (genericGroup == null) {
				genericGroup = new GenericGroup();
				genericGroup.name = name;
				genericGroup.fullValue = phonePortabilityDetails.size();
				map.put(name, genericGroup);
			}

			genericGroup.currentValue++;

		}
		List<GenericGroup> result = new ArrayList<GenericGroup>(map.values());

		Collections.sort(result, new Comparator<GenericGroup>() {
			@Override
			public int compare(GenericGroup arg0, GenericGroup arg1) {
				return (int) (arg1.currentValue - arg0.currentValue);
			}
		});

		return result;
	}

	public List<ContactPhone> getChangeContactNewPortability()
			throws CallOperatorException {
		List<ContactPhone> contactPhones = listAllContactPhone();
		if (contactPhones.size() == 0) {
			return Collections.emptyList();
		}
		ContactPhoneComparator comparator = new ContactPhoneComparator();
		Collections.sort(contactPhones, comparator);

		Set<Phone> phones = new HashSet<Phone>(contactPhones.size());
		for (ContactPhone contactPhone : contactPhones) {
			phones.add(contactPhone.phone);
		}

		List<ContactPhone> result = new ArrayList<ContactPhone>();

		List<PhonePortabilityDetail> phonePortabilityDetails = callOperatorService
				.getLastPhonePortabilityDetail(phones);
		ContactPhone contactPhoneTmp = new ContactPhone();

		for (PhonePortabilityDetail phonePortabilityDetail : phonePortabilityDetails) {
			contactPhoneTmp.phone = phonePortabilityDetail.getPhone();
			int index = Collections.binarySearch(contactPhones,
					contactPhoneTmp, comparator);
			if (index >= 0) {
				ContactPhone contactPhone = contactPhones.get(index);
				String name = phonePortabilityDetail.getPhoneOperator()
						.getName();
				if (contactPhone.labelType != Contacts.Phones.TYPE_CUSTOM
						|| (!contactPhone.label.equalsIgnoreCase(name))) {
					contactPhone.label = name.toUpperCase();
					contactPhone.labelType = Contacts.Phones.TYPE_CUSTOM;
					result.add(contactPhone);
				}
			}
		}
		return result;
	}

	public abstract List<ContactPhone> listAllContactPhone();

	@SuppressWarnings("unchecked")
	public List<CallPhone> listCallPhone(SearchCallPhone searchCallPhone) {

		Cursor cursor = null;
		StringBuilder selection = new StringBuilder();
		if (searchCallPhone.type != SearchCallPhone.ALL_TYPE) {
			selection.append(CallLog.Calls.TYPE);
			selection.append(" = ");
			selection.append(searchCallPhone.type);
		}

		if (searchCallPhone.startDate > 0) {
			if (selection.length() > 0) {
				selection.append(" AND ");
			}
			selection.append(CallLog.Calls.DATE);
			selection.append(" >= ");
			selection.append(searchCallPhone.startDate);
		}

		if (searchCallPhone.endDate > 0) {
			if (selection.length() > 0) {
				selection.append(" AND ");
			}
			selection.append(CallLog.Calls.DATE);
			selection.append(" <= ");
			selection.append(searchCallPhone.endDate);
		}

		try {
			cursor = context.getContentResolver().query(
					CallLog.Calls.CONTENT_URI,
					new String[] { CallLog.Calls.NUMBER, CallLog.Calls.DATE,
							CallLog.Calls.DURATION },
					selection.length() > 0 ? selection.toString() : null, null,
					CallLog.Calls.NUMBER + " ASC ");
			int count = cursor.getCount();

			if (count == 0) {
				return Collections.EMPTY_LIST;
			}
			List<CallPhone> callPhones = new ArrayList<CallPhone>(count);
			String dddDefault = getDDDDefault();
			while (cursor.moveToNext()) {
				try {
					CallPhone callPhone = new CallPhone();
					String number = cursor.getString(0);
					callPhone.number = PhoneUtils.parser(number, dddDefault,
							"55");
					callPhone.date = cursor.getLong(1);
					callPhone.duration = cursor.getLong(2);
					callPhones.add(callPhone);
				} catch (ParseException e) {
					e.printStackTrace();
				}
			}
			return callPhones;
		} finally {
			cursor.close();
		}
	}

	public List<GenericGroup> callPhoneGroupOperator(
			SearchCallPhone searchCallPhone) throws CallOperatorException {
		List<CallPhone> callPhones = listCallPhone(searchCallPhone);
		if (callPhones.size() == 0) {
			return Collections.emptyList();
		}

		Set<Phone> phonesSet = new HashSet<Phone>(callPhones.size());
		for (CallPhone callPhone : callPhones) {
			phonesSet.add(callPhone.number);
		}

		List<PhonePortabilityDetail> phonePortabilityDetails = callOperatorService
				.getLastPhonePortabilityDetail(phonesSet);

		CallPhoneComparator callPhoneComparator = new CallPhoneComparator();
		Collections.sort(callPhones, callPhoneComparator);

		Map<String, GenericGroup> map = new HashMap<String, GenericGroup>();

		CallPhone tmp = new CallPhone();
		long fullDuration = 0;
		for (PhonePortabilityDetail phonePortabilityDetail : phonePortabilityDetails) {
			PhoneOperator phoneOperator = phonePortabilityDetail
					.getPhoneOperator();
			Phone phone = phonePortabilityDetail.getPhone();
			tmp.number = phone;
			String name = phoneOperator.getName().trim().toUpperCase();
			GenericGroup genericGroup = map.get(name);
			if (genericGroup == null) {
				genericGroup = new GenericGroup();
				genericGroup.name = name;
				map.put(name, genericGroup);
			}
			int index = Collections.binarySearch(callPhones, tmp,
					callPhoneComparator);

			int indexLast = index + 1;
			while (index >= 0 && callPhones.get(index).number.equals(phone)) {
				CallPhone callPhone = callPhones.get(index);
				genericGroup.currentValue += callPhone.duration;
				fullDuration += callPhone.duration;
				index--;
			}

			while (indexLast >= 0 && indexLast < callPhones.size()
					&& callPhones.get(indexLast).number.equals(phone)) {
				CallPhone callPhone = callPhones.get(indexLast);
				genericGroup.currentValue += callPhone.duration;
				fullDuration += callPhone.duration;
				indexLast++;
			}

		}
		List<GenericGroup> result = new ArrayList<GenericGroup>(map.values());

		for (GenericGroup genericGroup : result) {
			genericGroup.fullValue = fullDuration;
		}
		Collections.sort(result, new Comparator<GenericGroup>() {
			@Override
			public int compare(GenericGroup arg0, GenericGroup arg1) {
				return (int) (arg1.currentValue - arg0.currentValue);
			}
		});
		return result;
	}

}
